package graphics;

import java.awt.*;
import java.awt.geom.*;
import java.util.*;

public class GraficPainter {

	public final static Boolean drawMonitor = new Boolean(true);

	public static final Stroke line = new BasicStroke();
	public static final Stroke dashed = new BasicStroke(1,BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 
			1.0f, new float[]{5.0f,15.0f},0f);
	
	public static void drawGrafic(Graphics2D g2, Point2D start, Point2D dim, boolean logx, boolean logy, ArrayList<Double> ...lists) {
		
		g2.setColor(Color.WHITE);
		g2.fillRect((int)start.getX(), (int)start.getY(), (int)dim.getX(), (int)dim.getY());
		g2.setColor(Color.BLACK);

		g2.drawRect((int)start.getX(), (int)start.getY(), (int) dim.getX(), (int) dim.getY());
		
		if (lists.length<=0)
			return;
		
		if (lists[0].size() <= 1)
			return;
		synchronized (drawMonitor) {

			double max = Double.NEGATIVE_INFINITY;//2.0/(Mode.teamNb+1);//Double.NEGATIVE_INFINITY;
			double min = Double.POSITIVE_INFINITY;
			final int PODEOCI = 10;
			
			for(ArrayList<Double> list : lists)
				for (double d : list) {
					max = Math.max(max, d);
					min = Math.min(min, d);
				}
		
			g2.translate(start.getX(), start.getY());

			Path2D[] paths = new Path2D[lists.length];
			for(int i = 0;i<lists.length;i++)
				paths[i] = new Path2D.Double();
			
			int maxxx = (true | !logx)?lists[0].size():Math.max(16, Integer.highestOneBit(lists[0].size())<<1);
			double dx = dim.getX() / scaleX(maxxx,1, logx);
			double dy = dim.getY() / (scaleY(max, 1, min, logy)-scaleY(min, 1, min, logy));
			
			//pochetak X
			g2.drawString("0", 0, (int)(1.04*dim.getY()));

			//podeoci X
			if (logx) {
				
				g2.setStroke(dashed);
				for(int i = 10;i*1.1<maxxx;i*=10) {
					int pozx = (int)scaleX(i, dx, logx);
					g2.drawString(i+"", pozx-10, (int)(1.04*dim.getY()));
					g2.drawLine(pozx,0,pozx,(int)dim.getY());					
				}
				for(int i = 20;i*1.1<maxxx;i*=10) {
					int pozx = (int)scaleX(i, dx, logx);
					g2.drawString(i+"", pozx-10, (int)(1.04*dim.getY()));
					g2.drawLine(pozx,0,pozx,(int)dim.getY());					
				}				
				for(int i = 5;i*1.1<maxxx;i*=10){
					int pozx = (int)scaleX(i, dx, logx);
					g2.drawString(i+"", pozx-10, (int)(1.04*dim.getY()));
					g2.drawLine(pozx,0,pozx,(int)dim.getY());					
				}
				g2.setStroke(line);
			}
			else {
				for(int i = 1; i<PODEOCI; i++)
					g2.drawString(i*maxxx/PODEOCI+"", (int)scaleX(i*maxxx/PODEOCI, dx, logx), (int)(1.04*dim.getY()));
			}
			
			//kraj X
			g2.drawString(maxxx + "", (int)(0.98*dim.getX()), (int)(1.04*dim.getY()));
			//------------------
			//pochetak Y
			g2.drawString(String.format("%5.3f",-min), -50, (int)(0.01*dim.getY()));

			//podeoci Y
			for(int i = 1; i<PODEOCI; i++)
				g2.drawString(String.format("%5.3f",(-min + i*(-max+min)/PODEOCI)), -50, (int)scaleY((min + (max-min)*i/PODEOCI), dy, min, logy));

			//kraj Y
			g2.drawString(String.format("%5.3f",-max), -50, (int)(0.99*dim.getY()));

			for(int i = 0;i<lists.length;i++)
				paths[i].moveTo(scaleX(0, dx, logx), scaleY(lists[i].get(0), dy, min, logy));

			int step = Math.max(1,Integer.highestOneBit(lists[0].size())>>8);
			
			for(int k = 0;k<lists.length;k++)
				for (int i = 1; i < lists[k].size(); i+=(i>128)?step:1)
					paths[k].lineTo(scaleX(i, dx, logx), scaleY(lists[k].get(i), dy, min, logy));
				
			for(int k = lists.length-1;k>=0;k--) {
				g2.setColor(colors[k]);
				g2.draw(paths[k]);
			}
			g2.translate(-start.getX(), -start.getY());
//			System.out.println(min + " " + max);			
		}
	}
	
	public static final Color[] colors = new Color[]{Color.BLUE, Color.RED, new Color(100, 100, 100), new Color(0,170,0), Color.PINK};
	
	private static double scaleX(double x, double dx, boolean logx) 
	{
		return logx?scaleLogShift(x,dx,10):scaleLin(x, dx);
	}

	private static double scaleY(double y, double dy, double min, boolean logy) 
	{
		return logy?scaleLogShift(y, dy, 10):scaleLin(y-min,dy);
	}
	
	private static double scaleLog(double v, double dv) {
		return Math.log(v+1) * dv;
	}
	
	private static double scaleLogShift(double v, double dv, double shift) {
		return (Math.log(v+1 + shift) - Math.log(shift+1)) * dv;
	}
	
	
	private static double scaleLin(double v, double dv) {
		return v * dv;
	}
	
	
}
